﻿#ifndef _XYFIFO_H_
#define _XYFIFO_H_



// C++11风格的FIFO

template <typename T> //para T is fifo store type
class  XyFifo
{
public:
    // initial fifo size
    XyFifo(unsigned int size)                   
    {
        _fifoInputIndex = 0;
        _fifoOutputIndex = 0;
        _currentFifoHead = 0;
        _bufferSize = size+1;
        _fifoBuffer = new T[_bufferSize];
    };

    ~XyFifo()
    {
        delete[]_fifoBuffer;
        _fifoBuffer = nullptr;
    };

    //check whether the fifo is write full
    bool isWriteFull()
    {
        auto inputIndex = _fifoInputIndex;

        auto temp = (++inputIndex >= _bufferSize) ? 0 : inputIndex;

        if (temp == _fifoOutputIndex)
        {
            return true;
        }

        return false;
    };
    //check whether the fifo is read empty
    bool isReadEmpty()
    {
        return (_fifoInputIndex == _fifoOutputIndex) ? true : false;
    };

    //write data to fifo,if the fifo is write full return false ,others return true
    //parameter bIntact ,true :write all data in once,if the fifo space not enough return false,or else return true
    //if bIntact is false ,write data one by one,if fifo write full return false,or else return true.
    bool writeData(const T* pdata, unsigned int len, bool bIntact = false)
    {
        auto inData = pdata;

        if (bIntact)
        {
            if (!isWriteSpaceEnough(len))
            {
                return false;
            }
            for (unsigned int i=0; i < len; i++)
            {
                _fifoBuffer[_fifoInputIndex++] = *inData++;

                if (_fifoInputIndex >= _bufferSize)
                {
                    _fifoInputIndex = 0;
                }
            }
        }
        else
        {
            for (unsigned int i=0; i < len; i++)
            {
                if (!isWriteFull())
                {
                    _fifoBuffer[_fifoInputIndex++] = *inData++;

                    if (_fifoInputIndex >= _bufferSize)
                    {
                        _fifoInputIndex = 0;
                    }
                }
                else
                {
                    return false;
                }
            }

        }
        return true;
    };
    //write one data only
    bool writeOneData(const T data)
    {
        if (!isWriteFull())
        {
            _fifoBuffer[_fifoInputIndex++] = data;

            if (_fifoInputIndex >= _bufferSize)
            {
                _fifoInputIndex = 0;
            }

            return true;
        }

        else
        {
            return false;
        }
    }


    //read data from fifo ,if it is not read empty,return true ,or else return false 
    bool readData(T* pdata,unsigned int len)
    {
        if (!isReadSpaceEnough(len))
        {
            return false;
        }
        auto pOutBuffer = pdata;

        for (unsigned int i = 0; i < len;i++)
        {
            *pOutBuffer++ = _fifoBuffer[_fifoOutputIndex++];

            if (_fifoOutputIndex>=_bufferSize)
            {
                _fifoOutputIndex = 0;
            }
        }

        return true;

    };
    //read one data only
    bool readOneData(T& outData)
    {
        if (!isReadSpaceEnough(1))
        {
            return false;
        }

        outData = _fifoBuffer[_fifoOutputIndex++];

        if (_fifoOutputIndex >= _bufferSize)
        {
            _fifoOutputIndex = 0;
        }

        return true;

    };

    //get fifo size
    const unsigned int getBufferSize(){ return _bufferSize; };

    //clear fifo 
    void resetFifo()
    {
        _fifoInputIndex = 0;
        _fifoOutputIndex = 0;
        memset(_fifoBuffer, 0, sizeof(_fifoBuffer));
    }

    //resize the fifo size
    void resizeFifo(unsigned int len)
    {
        resetFifo();

        if (len+1 == _bufferSize)
        {
            return;
        }

        if (_fifoBuffer)
        {
            delete[]_fifoBuffer;
        }
        _bufferSize = len+1;

        _fifoBuffer = new T[_bufferSize];

    }


private:
    T *_fifoBuffer;
    unsigned int _fifoInputIndex;
    unsigned int _fifoOutputIndex;
    unsigned int _currentFifoHead;
    unsigned int _bufferSize;

public:
    const unsigned int getWriteSpace()  
    {

        if (isWriteFull())
        {
            return 0;
        }

        auto surplus = (_fifoInputIndex >= _fifoOutputIndex)
         ? (_bufferSize - _fifoInputIndex + _fifoOutputIndex)
            : (_fifoOutputIndex - _fifoInputIndex);

        return surplus;
    }

    const bool isWriteSpaceEnough(unsigned int len)
    {
        return (getWriteSpace() >= len) ? true : false;
    }

    const unsigned int getReadSpace() 
    {

        if (isReadEmpty())
        {
            return 0;
        }

        auto surplus = (_fifoInputIndex >= _fifoOutputIndex) ? (_fifoInputIndex - _fifoOutputIndex)
            : (_bufferSize - _fifoOutputIndex + _fifoInputIndex);

        return surplus;
    }

    const bool isReadSpaceEnough(unsigned int len)
    {
        return (getReadSpace() >= len) ? true : false;
    }
};




#endif // !_XYFIFO_H_
